home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / apml / part04 < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  45.7 KB

  1. Path: xanth!mcnc!gatech!ukma!cwjcc!hal!ncoast!allbery
  2. From: ljz@fxgrp.UUCP (Lloyd Zusman)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i117: Arbitrary Precision Math Library -- 4 of 5
  5. Message-ID: <8810051945.AA05747@fxgrp.fx.com>
  6. Date: 7 Oct 88 00:14:23 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: ljz@fxgrp.UUCP (Lloyd Zusman)
  9. Lines: 1904
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 4, Issue 117
  13. Submitted-by: "Lloyd Zusman" <ljz@fxgrp.UUCP>
  14. Archive-name: apml/Part4
  15.  
  16. Enclosed you will find the Arbitrary Precision Math Library (4 of 5)
  17.  
  18. Please post this to the comp.sources.misc newsgroup.
  19.  
  20. I finally got this into good enough shape to send out to the net. To use,
  21. just unshar the 5 pieces, read the README file, possibly alter the makefiles
  22. to conform to your system's conventions, and then type 'make test'.
  23.  
  24. Good luck!
  25.  
  26. --
  27.   Lloyd Zusman                  Internet:  ljz@fx.com
  28.   Master Byte Software                  or ljz%fx.com@ames.arc.nasa.gov
  29.   Los Gatos, California                 or fxgrp!ljz@ames.arc.nasa.gov
  30.   "We take things well in hand."    uucp:  ...!ames!fxgrp!ljz
  31.   [ our Internet connection is down: use uucp or mail to the entry above it ]
  32.  
  33. #--------------------------Cut Here--------------------------
  34. #! /bin/sh
  35. # This is a shell archive.  Remove anything before the "#! /bin/sh" line,
  36. # then unpack it by saving it in a file and typing "sh file."
  37. #
  38. # Wrapped by Lloyd Zusman (ljz) at fxgrp on Wed Oct  5 12:41:51 1988
  39. #
  40. # unpacks with default permissions
  41. #
  42. # Contents : muldiv.c utils.c
  43. #
  44. if `test ! -s muldiv.c`
  45. then
  46. echo "x - muldiv.c"
  47. sed 's/^X//' > muldiv.c << '@\END_OF_FILE_muldiv.c'
  48. X/******************************************************************************
  49. X
  50. X    Arbitrary Precision Math Library General Public License
  51. X            (Written October 5, 1988)
  52. X
  53. X Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  54. X Gatos, California.  Everyone is permitted to copy and distribute
  55. X verbatim copies of this license, but changing it is not allowed.
  56. X You can also use this wording to make the terms for other programs.
  57. X
  58. X The wording of this license is based on that of the
  59. X "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
  60. X Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
  61. X but since some of the text has been changed, please be sure to
  62. X READ THIS CAREFULLY!
  63. X
  64. X  This general public license is intended to give everyone the right
  65. Xto share the Arbitrary Precision Math Library (hereinafter referred to
  66. Xas the "APM Library").  To make sure that you get the rights we want
  67. Xyou to have, I need to make restrictions that forbid anyone to deny
  68. Xyou these rights or to ask you to surrender the rights.
  69. X
  70. X  Specifically, we want to make sure that you have the right to give
  71. Xaway copies of the APM Library, that you receive source code or else
  72. Xcan get it if you want it, that you can change the APM Library or use
  73. Xpieces of it in new programs, and that you know you can do these
  74. Xthings.
  75. X
  76. X  To make sure that everyone has such rights, we have to forbid you to
  77. Xdeprive anyone else of these rights.  For example, if you distribute
  78. Xcopies of the APM Library, you must give the recipients all the
  79. Xrights that you have.  You must make sure that they, too, receive or
  80. Xcan get the source code.  And you must tell them their rights.
  81. X
  82. X  Also, for our own protection, we must make certain that everyone
  83. Xfinds out that there is no warranty for the APM Library.  If the APM
  84. XLibrary is modified by someone else and passed on, we want its
  85. Xrecipients to know that what they have is not what we distributed, so
  86. Xthat any problems introduced by others will not reflect on our
  87. Xreputation.
  88. X
  89. X  Therefore we (Lloyd Zusman and Master Byte Software) make the
  90. Xfollowing terms which say what you must do to be allowed to
  91. Xdistribute or change the APM Library.
  92. X
  93. X            COPYING POLICIES
  94. X
  95. X1. You may copy and distribute verbatim copies of the APM Library
  96. Xsource code as you receive it, in any medium, provided that you
  97. Xconspicuously and appropriately publish on each copy a valid copyright
  98. Xnotice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  99. XGatos, California" (or with whatever year is appropriate); keep intact
  100. Xthe notices on all files that refer to this License Agreement and to
  101. Xthe absence of any warranty; and give any other recipients of the the
  102. XAPM Library program a copy of this License Agreement along with the
  103. Xprogram.  You may charge a distribution fee for the physical act of
  104. Xtransferring a copy.
  105. X
  106. X  2. You may modify your copy or copies of the APM Library source code or
  107. Xany portion of it, and copy and distribute such modifications under
  108. Xthe terms of Paragraph 1 above, provided that you also do the following:
  109. X
  110. X    a) cause the modified files to carry prominent notices stating
  111. X    that you changed the files and the date of any change; and
  112. X
  113. X    b) cause the whole of any work that you distribute or publish, that in
  114. X    whole or in part contains or is a derivative of the APM Library or any
  115. X    part thereof, to be licensed to all third parties on terms identical
  116. X    to those contained in this License Agreement (except that you may
  117. X    choose to grant more extensive warranty protection to some or all
  118. X    third parties, at your option).
  119. X
  120. X    c) You may charge a distribution fee for the physical act of
  121. X    transferring a copy, and you may at your option offer warranty
  122. X    protection in exchange for a fee.
  123. X
  124. X    d) You may not charge a license fee for the whole of any work that
  125. X    you distribute or publish, that in whole or in part contains or is
  126. X    a derivative of the APM library or any part thereof, without the
  127. X    express written permission of Lloyd Zusman and Master Byte Software;
  128. X    whether this permission is granted for free or in return for goods
  129. X    services, royalties, or other compensation will be determined
  130. X    solely by Lloyd Zusman and Master Byte Software.
  131. X
  132. XMere aggregation of another unrelated program with this program (or its
  133. Xderivative) on a volume of a storage or distribution medium does not bring
  134. Xthe other program under the scope of these terms.
  135. X
  136. X  3. You may copy and distribute the APM Library (or a portion or
  137. Xderivative of it, under Paragraph 2) in object code or executable form
  138. Xunder all the terms of Paragraphs 1 and 2 above provided that you also
  139. Xdo one of the following:
  140. X
  141. X    a) accompany it with the complete corresponding machine-readable
  142. X    source code, which must be distributed under the terms of
  143. X    Paragraphs 1 and 2 above; or,
  144. X
  145. X    b) accompany it with a written offer, valid for at least three
  146. X    years, to give any third party free (except for a nominal
  147. X    shipping charge) a complete machine-readable copy of the
  148. X    corresponding source code, to be distributed under the terms of
  149. X    Paragraphs 1 and 2 above; or,
  150. X
  151. X    c) accompany it with the information you received as to where the
  152. X    corresponding source code may be obtained.  (This alternative is
  153. X    allowed only for noncommercial distribution and only if you
  154. X    received the program in object code or executable form alone.)
  155. X
  156. XFor an executable file, complete source code means all the source code
  157. Xfor all modules it contains; but, as a special exception, it need not
  158. Xinclude source code for modules which are standard libraries that
  159. Xaccompany the operating system on which the executable file runs.
  160. X
  161. X  4. You may not copy, sublicense, distribute or transfer the APM
  162. XLibrary except as expressly provided under this License Agreement.
  163. XAny attempt otherwise to copy, sublicense, distribute or transfer the
  164. XAPM Library is void and your rights to use the APM Library under this
  165. XLicense agreement shall be automatically terminated.  However, parties
  166. Xwho have received computer software programs from you with this
  167. XLicense Agreement will not have their licenses terminated so long as
  168. Xsuch parties remain in full compliance.
  169. X
  170. X  5. If you wish to incorporate parts of the APM Library into other
  171. Xprograms whose distribution conditions are different, write to Lloyd
  172. XZusman at Master Byte Software.  We have not yet worked out a simple
  173. Xrule that can be stated here, but we will often permit this.  We will
  174. Xbe guided by the goals of (1) preserving the free status of all
  175. Xderivatives of our free software; of (2) promoting the sharing and
  176. Xreuse of software; and of (3) not allowing anyone to profit from the
  177. Xuse of our software without us also having the opportunity to share
  178. Xin these profits.
  179. X
  180. XYour comments and suggestions about our licensing policies and our
  181. Xsoftware are welcome!  Please contact Lloyd Zusman, Master Byte
  182. XSoftware, 127 Wilder Ave., Los Gatos, California 95030, or call
  183. X(408) 395-5693.
  184. X
  185. X               NO WARRANTY
  186. X
  187. X  BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
  188. XABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
  189. XLAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
  190. XLLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
  191. XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  192. XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  193. XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  194. XAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE THE APM
  195. XLIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
  196. XSERVICING, REPAIR OR CORRECTION.
  197. X
  198. X  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
  199. XSOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
  200. XREDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
  201. XDAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
  202. XINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
  203. XINABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
  204. XBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
  205. XFAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
  206. XMASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
  207. XTHE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  208. X
  209. X******************************************************************************/
  210. X
  211. X
  212. X/*
  213. X * Multiplication and division routines for the APM library.
  214. X *
  215. X * $Log:    muldiv.c,v $
  216. X * Revision 1.0  88/10/05  12:38:15  ljz
  217. X * Initial release.
  218. X * 
  219. X */
  220. X#ifndef lint
  221. Xstatic char rcsid[] = "$Header: muldiv.c,v 1.0 88/10/05 12:38:15 ljz Exp $";
  222. X#endif /* ! lint */
  223. X
  224. X#include <stdio.h>
  225. X#include "apm.h"
  226. X#include "apmlocal.h"
  227. X
  228. Xint
  229. Xapm_multiply(result, num1, num2)
  230. XAPM result;
  231. XAPM num1;
  232. XAPM num2;
  233. X{
  234. X    int length1;
  235. X    int length2;
  236. X    int len;
  237. X    int dp;
  238. X    int n1;
  239. X    int n2;
  240. X    int sum;
  241. X    short sign;
  242. X    short base;
  243. X    short carry;
  244. X    long tempval;
  245. X
  246. X    apm_errno = APM_OK;
  247. X
  248. X    ERR_RETURN(APM_val_format(result));
  249. X    ERR_RETURN(apm_validate(num1));
  250. X    ERR_RETURN(apm_validate(num2));
  251. X
  252. X    if (num1->base != num2->base) {
  253. X        return (APM_error(APM_EBASE));
  254. X    }
  255. X
  256. X    if (result == num1 || result == num2) {
  257. X        return (APM_error(APM_EOVERLAP));
  258. X    }
  259. X
  260. X    base = num1->base;
  261. X
  262. X    sign = SIGNOF(num1->sign) * SIGNOF(num2->sign);
  263. X
  264. X    ERR_RETURN(APM_trim(num1, 1, 1));
  265. X    ERR_RETURN(APM_trim(num2, 1, 1));
  266. X
  267. X    length1 = num1->length;
  268. X    length2 = num2->length;
  269. X    
  270. X    len = length1 + length2;
  271. X    dp = num1->dp + num2->dp;
  272. X
  273. X    ERR_RETURN(APM_size(result, len));
  274. X
  275. X    APM_zero_shorts(result->data, len);
  276. X
  277. X    for (n1 = 0; n1 < length1; ++n1) {
  278. X        carry = 0;
  279. X        sum = n1;
  280. X        for (n2 = 0; n2 < length2; ++n2, ++sum) {
  281. X            tempval = num1->data[n1];
  282. X            tempval *= num2->data[n2];
  283. X            tempval += result->data[sum] + carry;
  284. X            result->data[sum] =
  285. X                (short)(tempval % base);
  286. X            carry =
  287. X                (short)(tempval / base);
  288. X        }
  289. X        result->data[sum] = carry;
  290. X    }
  291. X
  292. X    result->length = len;
  293. X    result->dp = dp;
  294. X    result->base = base;
  295. X    result->sign = sign;
  296. X
  297. X    return (APM_error(APM_trim(result, 1, 1)));
  298. X}
  299. X
  300. X/*
  301. X * For division, I use the algorithm described in Knuth, "The Art of
  302. X * Computer Programming, Volume 2, Seminumerical Algorithms", second
  303. X * edition, pp. 255-260.
  304. X */
  305. Xint
  306. Xapm_divide(result, frac_precision, remainder, num1, num2)
  307. XAPM result;
  308. Xint frac_precision;
  309. XAPM remainder;
  310. XAPM num1;
  311. XAPM num2;
  312. X{
  313. X    static APM temp = (APM)NULL;
  314. X    static short *dividend = (short *)NULL;
  315. X    static int dividendLength = 0;
  316. X    static short *divisor = (short *)NULL;
  317. X    static short *xdivisor = (short *)NULL;
  318. X    static int divisorLength = 0;
  319. X
  320. X    int i;
  321. X    int j;
  322. X    int n;
  323. X    int uJ;
  324. X    int vJ;
  325. X    int M;
  326. X    int N;
  327. X    int MplusN;
  328. X    int Nplus1;
  329. X    int MplusNplus1;
  330. X    int length1;
  331. X    int length2;
  332. X    int offset;
  333. X    int left;
  334. X    int frac;
  335. X    short divN1;
  336. X    short divN2;
  337. X    short sign;
  338. X    short base;
  339. X    short scaleFactor;
  340. X    short borrow;
  341. X    short qHat;
  342. X    long temp1;
  343. X    long temp2;
  344. X    long temp3;
  345. X
  346. X    apm_errno = APM_OK;
  347. X
  348. X    if (frac_precision <= 0) {
  349. X        return (APM_set_errno(APM_EPARM));
  350. X    }
  351. X
  352. X    ERR_RETURN(APM_val_format(result));
  353. X    if (remainder != NULL) {
  354. X        ERR_RETURN(APM_val_format(remainder));
  355. X    }
  356. X    ERR_RETURN(apm_validate(num1));
  357. X    ERR_RETURN(apm_validate(num2));
  358. X
  359. X    if (result == remainder || result == num1 || result == num2) {
  360. X        return (APM_error(APM_EOVERLAP));
  361. X    }
  362. X    if (remainder == num1 || remainder == num2) {
  363. X        return (APM_error(APM_EOVERLAP));
  364. X    }
  365. X
  366. X    base = num1->base;
  367. X
  368. X    ERR_RETURN(APM_trim(num2, 1, 1));
  369. X    if (num2->length <= 0) {
  370. X        /*
  371. X         * Division by zero.
  372. X         */
  373. X        result->length = 0;
  374. X        result->dp = 0;
  375. X        result->base = base;
  376. X        if (remainder != (APM)NULL) {
  377. X            remainder->length = 0;
  378. X            remainder->dp = 0;
  379. X            remainder->base = base;
  380. X        }
  381. X        return (APM_error(APM_WDIVBYZERO));
  382. X    }
  383. X
  384. X    ERR_RETURN(APM_trim(num1, 1, 1));
  385. X    if (num1->length <= 0) {
  386. X        /*
  387. X         * Dividend is zero, so result is zero.
  388. X         */
  389. X        result->length = 0;
  390. X        result->dp = 0;
  391. X        result->base = base;
  392. X        if (remainder != (APM)NULL) {
  393. X            remainder->length = 0;
  394. X            remainder->dp = 0;
  395. X            remainder->base = base;
  396. X        }
  397. X        return (APM_OK);
  398. X    }
  399. X
  400. X    sign = num1->sign * num2->sign;
  401. X
  402. X    length1 = num1->length;
  403. X    length2 = num2->length;
  404. X    for (offset = length2; offset > 0; --offset) {
  405. X        if (num2->data[offset - 1] != 0) {
  406. X            break;
  407. X        }
  408. X    }
  409. X
  410. X    offset = length2 - offset;
  411. X
  412. X    frac = frac_precision;
  413. X    if (base == SPECIAL_BASE) {
  414. X        frac = (frac + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE;
  415. X    }
  416. X
  417. X    
  418. X    left = (length1 - num1->dp) - (length2 - num1->dp);
  419. X    if (left < 0) {
  420. X        left = 0;
  421. X    }
  422. X
  423. X    M = frac + left + 1;
  424. X    if (M < length1) {
  425. X        M = length1;
  426. X    }
  427. X
  428. X    N = (length2 - offset) + 1;
  429. X    Nplus1 = N + 1;
  430. X    MplusN = M + N;
  431. X    MplusNplus1 = MplusN + 1;
  432. X
  433. X    if (temp == (APM)NULL) {
  434. X        temp = APM_alloc();
  435. X        if (temp == (APM)NULL) {
  436. X            return (APM_error(APM_ENOMEM));
  437. X        }
  438. X    }
  439. X
  440. X    ERR_RETURN(APM_size(temp, M + 1));
  441. X
  442. X    if (MplusNplus1 > dividendLength) {
  443. X        int xlen = MplusNplus1;
  444. X        if (xlen < 8) {
  445. X            xlen = 8;
  446. X        }
  447. X        if (dividendLength < 1) {
  448. X            dividend = (short *)APM_alloc_mem(NULL, xlen,
  449. X                        sizeof (short));
  450. X        }
  451. X        else {
  452. X            dividend = (short *)APM_alloc_mem(dividend, xlen,
  453. X                        sizeof (short));
  454. X        }
  455. X        if (dividend == (short *)NULL) {
  456. X            return (APM_error(APM_ENOMEM));
  457. X        }
  458. X        dividendLength = xlen;
  459. X    }
  460. X
  461. X    if (Nplus1 > divisorLength) {
  462. X        int xlen = Nplus1;
  463. X        if (xlen < 8) {
  464. X            xlen = 8;
  465. X        }
  466. X        if (divisorLength < 1) {
  467. X            divisor = (short *)APM_alloc_mem(NULL, xlen,
  468. X                              sizeof (short));
  469. X        }
  470. X        else {
  471. X            divisor = (short *)APM_alloc_mem(divisor, xlen,
  472. X                              sizeof (short));
  473. X        }
  474. X        if (divisor == (short *)NULL) {
  475. X            return (APM_error(APM_ENOMEM));
  476. X        }
  477. X        if (divisorLength < 1) {
  478. X            xdivisor = (short *)APM_alloc_mem(NULL, xlen,
  479. X                               sizeof (short));
  480. X        }
  481. X        else {
  482. X            xdivisor = (short *)APM_alloc_mem(xdivisor, xlen,
  483. X                               sizeof (short));
  484. X        }
  485. X        if (xdivisor == (short *)NULL) {
  486. X            return (APM_error(APM_ENOMEM));
  487. X        }
  488. X        divisorLength = xlen;
  489. X    }
  490. X
  491. X    i = MplusN - length1;
  492. X
  493. X    APM_zero_shorts(dividend, i);
  494. X    APM_copy_shorts(÷nd[i], num1->data, length1);
  495. X
  496. X    divisor[0] = 0;
  497. X    APM_copy_shorts(&divisor[1], num2->data, length2 - offset);
  498. X
  499. X    /*
  500. X     * Knuth: step D1.
  501. X     */
  502. X    scaleFactor = base / (divisor[N - 1] + 1);
  503. X    if (scaleFactor <= 1) {
  504. X        dividend[MplusN] = 0;
  505. X    }
  506. X    else {
  507. X        dividend[MplusN] = APM_scalar_mul(dividend, dividend,
  508. X                               MplusN,
  509. X                               scaleFactor, base);
  510. X        APM_scalar_mul(divisor, divisor, N, scaleFactor, base);
  511. X    }
  512. X
  513. X    divN1 = divisor[N - 1];
  514. X    divN2 = divisor[N - 2];
  515. X
  516. X    /*
  517. X     * Knuth: steps D2 and D7.
  518. X     */
  519. X    for (j = 0, vJ = M, uJ = MplusN; j <= M; ++j, --vJ, --uJ) {
  520. X        /*
  521. X         * Knuth: step D3.
  522. X         */
  523. X        temp1 = dividend[uJ];
  524. X        temp1 *= base;
  525. X        temp1 += dividend[uJ - 1];
  526. X
  527. X        if (dividend[uJ] == divN1) {
  528. X            qHat = base - 1;
  529. X        }
  530. X        else {
  531. X            temp2 = temp1 / divN1;
  532. X            qHat = (short)temp2;
  533. X        }
  534. X
  535. X        for (;;) {
  536. X            temp2 = divN2;
  537. X            temp2 *= qHat;
  538. X
  539. X            temp3 = divN1;
  540. X            temp3 *= qHat;
  541. X            temp3 = temp1 - temp3;
  542. X            temp3 *= base;
  543. X            temp3 += dividend[uJ - 2];
  544. X
  545. X            if (temp2 > temp3) {
  546. X                --qHat;
  547. X            }
  548. X            else {
  549. X                break;
  550. X            }
  551. X        }
  552. X
  553. X        /*
  554. X         * Knuth: step D4.
  555. X         */
  556. X        xdivisor[N] = APM_scalar_mul(xdivisor, divisor, N, qHat,
  557. X                          base);
  558. X        borrow = APM_array_sub(&(dividend[vJ]), xdivisor,
  559. X                   Nplus1, base);
  560. X
  561. X        /*
  562. X         * Knuth: step D5.
  563. X         */
  564. X        if (borrow == 0) {
  565. X            temp->data[vJ] = qHat;
  566. X        }
  567. X        else {
  568. X            /*
  569. X             * Knuth: step D6.
  570. X             */
  571. X            temp->data[vJ] = qHat - 1;
  572. X            divisor[N] = 0;
  573. X            APM_array_add(&(dividend[vJ]), divisor, Nplus1, base);
  574. X        }
  575. X    }
  576. X
  577. X    /*
  578. X     * Knuth: step D8.
  579. X     */
  580. X    temp->length = M + 1;
  581. X    temp->dp = (M - offset) -
  582. X        ((length1 - num1->dp) - (length2 - num2->dp));
  583. X    temp->base = base;
  584. X    temp->sign = sign;
  585. X
  586. X    ERR_RETURN(apm_round(result, temp, frac_precision));
  587. X    ERR_RETURN(APM_trim(result, 1, 1));
  588. X
  589. X    if (remainder != (APM)NULL) {
  590. X        ERR_RETURN(APM_size(temp, length2));
  591. X        if (scaleFactor > 1) {
  592. X            ERR_RETURN(APM_scalar_div(temp, ÷nd[1],
  593. X                             length2,
  594. X                             num2->dp,
  595. X                             num2->sign,
  596. X                             base, scaleFactor));
  597. X        }
  598. X        else {
  599. X            temp->length = length2;
  600. X            temp->dp = num2->dp;
  601. X            temp->sign = num2->sign;
  602. X            temp->base = base;
  603. X            APM_copy_shorts(temp->data, ÷nd[1], length2);
  604. X        }
  605. X        ERR_RETURN(apm_round(remainder, temp, frac_precision));
  606. X        ERR_RETURN(APM_trim(remainder, 1, 1));
  607. X    }
  608. X
  609. X    return (APM_OK);
  610. X}
  611. @\END_OF_FILE_muldiv.c
  612. else
  613.   echo "shar: Will not over write muldiv.c"
  614. fi
  615. if `test ! -s utils.c`
  616. then
  617. echo "x - utils.c"
  618. sed 's/^X//' > utils.c << '@\END_OF_FILE_utils.c'
  619. X/******************************************************************************
  620. X
  621. X    Arbitrary Precision Math Library General Public License
  622. X            (Written October 5, 1988)
  623. X
  624. X Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  625. X Gatos, California.  Everyone is permitted to copy and distribute
  626. X verbatim copies of this license, but changing it is not allowed.
  627. X You can also use this wording to make the terms for other programs.
  628. X
  629. X The wording of this license is based on that of the
  630. X "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
  631. X Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
  632. X but since some of the text has been changed, please be sure to
  633. X READ THIS CAREFULLY!
  634. X
  635. X  This general public license is intended to give everyone the right
  636. Xto share the Arbitrary Precision Math Library (hereinafter referred to
  637. Xas the "APM Library").  To make sure that you get the rights we want
  638. Xyou to have, I need to make restrictions that forbid anyone to deny
  639. Xyou these rights or to ask you to surrender the rights.
  640. X
  641. X  Specifically, we want to make sure that you have the right to give
  642. Xaway copies of the APM Library, that you receive source code or else
  643. Xcan get it if you want it, that you can change the APM Library or use
  644. Xpieces of it in new programs, and that you know you can do these
  645. Xthings.
  646. X
  647. X  To make sure that everyone has such rights, we have to forbid you to
  648. Xdeprive anyone else of these rights.  For example, if you distribute
  649. Xcopies of the APM Library, you must give the recipients all the
  650. Xrights that you have.  You must make sure that they, too, receive or
  651. Xcan get the source code.  And you must tell them their rights.
  652. X
  653. X  Also, for our own protection, we must make certain that everyone
  654. Xfinds out that there is no warranty for the APM Library.  If the APM
  655. XLibrary is modified by someone else and passed on, we want its
  656. Xrecipients to know that what they have is not what we distributed, so
  657. Xthat any problems introduced by others will not reflect on our
  658. Xreputation.
  659. X
  660. X  Therefore we (Lloyd Zusman and Master Byte Software) make the
  661. Xfollowing terms which say what you must do to be allowed to
  662. Xdistribute or change the APM Library.
  663. X
  664. X            COPYING POLICIES
  665. X
  666. X1. You may copy and distribute verbatim copies of the APM Library
  667. Xsource code as you receive it, in any medium, provided that you
  668. Xconspicuously and appropriately publish on each copy a valid copyright
  669. Xnotice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  670. XGatos, California" (or with whatever year is appropriate); keep intact
  671. Xthe notices on all files that refer to this License Agreement and to
  672. Xthe absence of any warranty; and give any other recipients of the the
  673. XAPM Library program a copy of this License Agreement along with the
  674. Xprogram.  You may charge a distribution fee for the physical act of
  675. Xtransferring a copy.
  676. X
  677. X  2. You may modify your copy or copies of the APM Library source code or
  678. Xany portion of it, and copy and distribute such modifications under
  679. Xthe terms of Paragraph 1 above, provided that you also do the following:
  680. X
  681. X    a) cause the modified files to carry prominent notices stating
  682. X    that you changed the files and the date of any change; and
  683. X
  684. X    b) cause the whole of any work that you distribute or publish, that in
  685. X    whole or in part contains or is a derivative of the APM Library or any
  686. X    part thereof, to be licensed to all third parties on terms identical
  687. X    to those contained in this License Agreement (except that you may
  688. X    choose to grant more extensive warranty protection to some or all
  689. X    third parties, at your option).
  690. X
  691. X    c) You may charge a distribution fee for the physical act of
  692. X    transferring a copy, and you may at your option offer warranty
  693. X    protection in exchange for a fee.
  694. X
  695. X    d) You may not charge a license fee for the whole of any work that
  696. X    you distribute or publish, that in whole or in part contains or is
  697. X    a derivative of the APM library or any part thereof, without the
  698. X    express written permission of Lloyd Zusman and Master Byte Software;
  699. X    whether this permission is granted for free or in return for goods
  700. X    services, royalties, or other compensation will be determined
  701. X    solely by Lloyd Zusman and Master Byte Software.
  702. X
  703. XMere aggregation of another unrelated program with this program (or its
  704. Xderivative) on a volume of a storage or distribution medium does not bring
  705. Xthe other program under the scope of these terms.
  706. X
  707. X  3. You may copy and distribute the APM Library (or a portion or
  708. Xderivative of it, under Paragraph 2) in object code or executable form
  709. Xunder all the terms of Paragraphs 1 and 2 above provided that you also
  710. Xdo one of the following:
  711. X
  712. X    a) accompany it with the complete corresponding machine-readable
  713. X    source code, which must be distributed under the terms of
  714. X    Paragraphs 1 and 2 above; or,
  715. X
  716. X    b) accompany it with a written offer, valid for at least three
  717. X    years, to give any third party free (except for a nominal
  718. X    shipping charge) a complete machine-readable copy of the
  719. X    corresponding source code, to be distributed under the terms of
  720. X    Paragraphs 1 and 2 above; or,
  721. X
  722. X    c) accompany it with the information you received as to where the
  723. X    corresponding source code may be obtained.  (This alternative is
  724. X    allowed only for noncommercial distribution and only if you
  725. X    received the program in object code or executable form alone.)
  726. X
  727. XFor an executable file, complete source code means all the source code
  728. Xfor all modules it contains; but, as a special exception, it need not
  729. Xinclude source code for modules which are standard libraries that
  730. Xaccompany the operating system on which the executable file runs.
  731. X
  732. X  4. You may not copy, sublicense, distribute or transfer the APM
  733. XLibrary except as expressly provided under this License Agreement.
  734. XAny attempt otherwise to copy, sublicense, distribute or transfer the
  735. XAPM Library is void and your rights to use the APM Library under this
  736. XLicense agreement shall be automatically terminated.  However, parties
  737. Xwho have received computer software programs from you with this
  738. XLicense Agreement will not have their licenses terminated so long as
  739. Xsuch parties remain in full compliance.
  740. X
  741. X  5. If you wish to incorporate parts of the APM Library into other
  742. Xprograms whose distribution conditions are different, write to Lloyd
  743. XZusman at Master Byte Software.  We have not yet worked out a simple
  744. Xrule that can be stated here, but we will often permit this.  We will
  745. Xbe guided by the goals of (1) preserving the free status of all
  746. Xderivatives of our free software; of (2) promoting the sharing and
  747. Xreuse of software; and of (3) not allowing anyone to profit from the
  748. Xuse of our software without us also having the opportunity to share
  749. Xin these profits.
  750. X
  751. XYour comments and suggestions about our licensing policies and our
  752. Xsoftware are welcome!  Please contact Lloyd Zusman, Master Byte
  753. XSoftware, 127 Wilder Ave., Los Gatos, California 95030, or call
  754. X(408) 395-5693.
  755. X
  756. X               NO WARRANTY
  757. X
  758. X  BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
  759. XABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
  760. XLAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
  761. XLLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
  762. XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  763. XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  764. XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  765. XAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE THE APM
  766. XLIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
  767. XSERVICING, REPAIR OR CORRECTION.
  768. X
  769. X  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
  770. XSOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
  771. XREDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
  772. XDAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
  773. XINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
  774. XINABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
  775. XBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
  776. XFAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
  777. XMASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
  778. XTHE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  779. X
  780. X******************************************************************************/
  781. X
  782. X
  783. X/*
  784. X * Low level utilities for the APM library.  The user never should call
  785. X * any of these directly.
  786. X *
  787. X * $Log:    utils.c,v $
  788. X * Revision 1.0  88/10/05  12:38:16  ljz
  789. X * Initial release.
  790. X * 
  791. X */
  792. X#ifndef lint
  793. Xstatic char rcsid[] = "$Header: utils.c,v 1.0 88/10/05 12:38:16 ljz Exp $";
  794. X#endif /* ! lint */
  795. X
  796. X#include <stdio.h>
  797. X#include <varargs.h>
  798. X#include "apm.h"
  799. X#include "apmlocal.h"
  800. X
  801. Xint apm_errno = APM_OK;
  802. Xint (*APM_error_func)() = (int (*)())NULL;
  803. Xint APM_line = 0;
  804. Xchar *APM_file = "";
  805. Xchar *APM_func_name = "";
  806. X
  807. Xstatic char APM_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  808. X
  809. X#define MAX_BASE    ((sizeof (APM_digits) / sizeof (APM_digits[0])) - 1)
  810. X
  811. Xchar *
  812. XAPM_error_message(code)
  813. Xint code;
  814. X{
  815. X    static char localMessage[80];
  816. X    char *message;
  817. X
  818. X    switch (code) {
  819. X    case APM_ENOMEM:
  820. X        message = "memory allocation failed";
  821. X        break;
  822. X    case APM_WNULL:
  823. X        message = "null argument";
  824. X        break;
  825. X    case APM_WDIVBYZERO:
  826. X        message = "division by zero";
  827. X        break;
  828. X    case APM_WTRUNC:
  829. X        message = "result truncated";
  830. X        break;
  831. X    case APM_WNOALLOC:
  832. X        message = "attempt to free unallocated APM value";
  833. X        break;
  834. X    case APM_EPARM:
  835. X        message = "invalid function parameter";
  836. X        break;
  837. X    case APM_ENULL:
  838. X        message = "null APM value";
  839. X        break;
  840. X    case APM_EBADVAL:
  841. X        message = "bad APM value";
  842. X        break;
  843. X    case APM_ENULLVAL:
  844. X        message = "null value";
  845. X        break;
  846. X    case APM_EFMT:
  847. X        message = "invalid string format";
  848. X        break;
  849. X    case APM_EBASE:
  850. X        message = "invalid base";
  851. X        break;
  852. X    case APM_ESIZE:
  853. X        message = "destination size is too small";
  854. X        break;
  855. X    case APM_EOVERLAP:
  856. X        message = "result overlaps one or more operands";
  857. X        break;
  858. X    default:
  859. X        sprintf(localMessage, "unknown error code: %d", code);
  860. X        message = localMessage;
  861. X        break;
  862. X    }
  863. X
  864. X    return (message);
  865. X}
  866. X
  867. Xint
  868. XAPM_set_errno(code)
  869. Xint code;
  870. X{
  871. X    apm_errno = code;
  872. X    return (code);
  873. X}
  874. X
  875. Xint
  876. XAPM_error(code)
  877. Xint code;
  878. X{
  879. X    code = APM_set_errno(code);
  880. X
  881. X    if (code != APM_OK && APM_error_func != (int (*)())NULL) {
  882. X        code = (*APM_error_func)(code,
  883. X                     APM_error_message(code),
  884. X                     APM_file, APM_line,
  885. X                     APM_func_name);
  886. X    }
  887. X    return (code);
  888. X}
  889. X
  890. Xchar *
  891. XAPM_trim_string(string)
  892. Xchar *string;
  893. X{
  894. X    char *orig = string;
  895. X    char *sp = string;
  896. X
  897. X    if (string != NULL) {
  898. X        for (; *string != '\0'; ++string) {
  899. X            if (*string != ' ' && *string != '\t') {
  900. X                sp = string + 1;
  901. X            }
  902. X        }
  903. X        *sp = '\0';
  904. X    }
  905. X
  906. X    return (orig);
  907. X}
  908. X
  909. Xchar *
  910. XAPM_left_justify(string, ignore)
  911. Xchar *string;
  912. Xchar *ignore;
  913. X{
  914. X    if (string != NULL && ignore != NULL) {
  915. X        for (; *string != '\0'; ++string) {
  916. X            if (APM_index(ignore, *string) == NULL) {
  917. X                break;
  918. X            }
  919. X        }
  920. X    }
  921. X
  922. X    return (string);
  923. X}
  924. X
  925. Xint
  926. XAPM_val_format(apm)
  927. XAPM apm;
  928. X{
  929. X    apm_errno = APM_OK;
  930. X
  931. X    if (apm == (APM)NULL) {
  932. X        return (APM_set_errno(APM_ENULL));
  933. X    }
  934. X    if (apm->magic != APM_MAGIC) {
  935. X        return (APM_set_errno(APM_EBADVAL));
  936. X    }
  937. X    return (APM_OK);
  938. X}
  939. X
  940. Xint
  941. XAPM_val_base(base)
  942. Xshort base;
  943. X{
  944. X    apm_errno = APM_OK;
  945. X
  946. X    if (base == SPECIAL_BASE) {
  947. X        return (APM_OK);
  948. X    }
  949. X
  950. X    if (base < 2 || base > MAX_BASE) {
  951. X        return (APM_set_errno(APM_EBASE));
  952. X    }
  953. X
  954. X    return (APM_OK);
  955. X}
  956. X
  957. Xshort
  958. XAPM_get_digit(ch, base)
  959. Xchar ch;
  960. Xshort base;
  961. X{
  962. X    int ercode;
  963. X    short idx;
  964. X
  965. X    ercode = APM_val_base(base);
  966. X    if (ercode < APM_OK) {
  967. X        return (APM_set_errno(ercode));
  968. X    }
  969. X
  970. X    if (base == SPECIAL_BASE) {
  971. X        base = 10;
  972. X    }
  973. X
  974. X    for (idx = 0; idx < base; ++idx) {
  975. X        if (ch == APM_digits[idx]) {
  976. X            return (idx);
  977. X        }
  978. X    }
  979. X
  980. X    return (APM_set_errno(APM_EBASE));
  981. X}
  982. X
  983. Xint
  984. XAPM_radix_pos(string, base)
  985. Xchar *string;
  986. Xshort base;
  987. X{
  988. X    int dp = -1;
  989. X    int nodigits = 1;
  990. X    int pos = 0;
  991. X    int ercode;
  992. X
  993. X    if (string == NULL) {
  994. X        return (APM_set_errno(APM_ENULLVAL));
  995. X    }
  996. X    ercode = APM_val_base(base);
  997. X    if (ercode < APM_OK) {
  998. X        return (ercode);
  999. X    }
  1000. X
  1001. X    for (; string[pos] != '\0'; ++pos) {
  1002. X        if (string[pos] == '.') {
  1003. X            if (dp >= 0) {
  1004. X                return (APM_set_errno(APM_EFMT));
  1005. X            }
  1006. X            else {
  1007. X                dp = pos;
  1008. X            }
  1009. X        }
  1010. X        else if (APM_get_digit(string[pos], base) < 0) {
  1011. X            return (APM_set_errno(APM_EFMT));
  1012. X        }
  1013. X        else {
  1014. X            nodigits = 0;
  1015. X        }
  1016. X    }
  1017. X
  1018. X    if (nodigits) {
  1019. X        return (APM_set_errno(APM_EFMT));
  1020. X    }
  1021. X
  1022. X    return (dp + 1);
  1023. X}
  1024. X
  1025. Xint
  1026. XAPM_shift(num, scaleFactor)
  1027. XAPM num;
  1028. Xint scaleFactor;
  1029. X{
  1030. X    int ercode;
  1031. X
  1032. X    apm_errno = APM_OK;
  1033. X
  1034. X    if (scaleFactor == 0) {
  1035. X        return (APM_OK);
  1036. X    }
  1037. X    if (num->base != 0 && num->base != SPECIAL_BASE) {
  1038. X        num->dp -= scaleFactor;
  1039. X    }
  1040. X    else {
  1041. X        /*
  1042. X         * The following code assumes that
  1043. X         * (-X) % Y == -(X % Y).
  1044. X         */
  1045. X        int factor = scaleFactor / SPECIAL_SCALE;
  1046. X        int n = scaleFactor % SPECIAL_SCALE;
  1047. X
  1048. X        if (scaleFactor < 0) {
  1049. X            --factor;
  1050. X            n += SPECIAL_SCALE;
  1051. X        }
  1052. X        num->dp -= factor;
  1053. X        if (n > 0) {
  1054. X            int multiplier = 1;
  1055. X            while (n-- > 0) {
  1056. X                multiplier *= 10;
  1057. X            }
  1058. X            n = (num->length)++;
  1059. X            ercode = APM_size(num, num->length);
  1060. X            if (ercode < APM_OK) {
  1061. X                return (ercode);
  1062. X            }
  1063. X            num->data[n] = APM_scalar_mul(num->data,
  1064. X                               num->data, n,
  1065. X                               multiplier,
  1066. X                               num->base);
  1067. X        }
  1068. X    }
  1069. X    return (APM_trim(num, 1, 1));
  1070. X}
  1071. X
  1072. Xint
  1073. XAPM_trimlead(apm)
  1074. XAPM apm;
  1075. X{
  1076. X    int n;
  1077. X    int ercode;
  1078. X
  1079. X    apm_errno = APM_OK;
  1080. X
  1081. X    if (apm == (APM)NULL) {
  1082. X        return (APM_set_errno(APM_ENULL));
  1083. X    }
  1084. X
  1085. X    if (apm->data == NULL) {
  1086. X        apm->length = 0;
  1087. X        return (APM_OK);
  1088. X    }
  1089. X
  1090. X    ercode = APM_normalize(apm);
  1091. X    if (ercode < APM_OK) {
  1092. X        return (APM_set_errno(ercode));
  1093. X    }
  1094. X
  1095. X    for (n = apm->length; n > 0; --n) {
  1096. X        if (apm->data[n - 1] != 0) {
  1097. X            break;
  1098. X        }
  1099. X    }
  1100. X
  1101. X    if (n < apm->length) {
  1102. X        apm->length = n;
  1103. X    }
  1104. X
  1105. X    return (APM_OK);
  1106. X}
  1107. X
  1108. Xint
  1109. XAPM_trimtrail(apm)
  1110. XAPM apm;
  1111. X{
  1112. X    int n;
  1113. X    int ercode;
  1114. X
  1115. X    apm_errno = APM_OK;
  1116. X
  1117. X    if (apm == (APM)NULL) {
  1118. X        return (APM_set_errno(APM_ENULL));
  1119. X    }
  1120. X
  1121. X    if (apm->data == NULL) {
  1122. X        apm->length = 0;
  1123. X        apm->dp = 0;
  1124. X        return (APM_OK);
  1125. X    }
  1126. X
  1127. X    ercode = APM_normalize(apm);
  1128. X    if (ercode < APM_OK) {
  1129. X        return (APM_set_errno(ercode));
  1130. X    }
  1131. X
  1132. X    for (n = 0; n < apm->dp; ++n) {
  1133. X        if (apm->data[n] != 0) {
  1134. X            break;
  1135. X        }
  1136. X    }
  1137. X
  1138. X    if (n == 0) {    /* no trailing zeros */
  1139. X        return (APM_OK);
  1140. X    }
  1141. X
  1142. X    /*
  1143. X     * Shift down by 'n', subtracting this from apm->length and
  1144. X     * apm->dp.
  1145. X     */
  1146. X    apm->length -= n;
  1147. X    apm->dp -= n;
  1148. X    APM_copy_shorts(apm->data, &(apm->data[n]), apm->length);
  1149. X    APM_zero_shorts(&(apm->data[apm->length]), n);
  1150. X
  1151. X    return (APM_OK);
  1152. X}
  1153. X
  1154. Xint
  1155. XAPM_trim(apm, lead, trail)
  1156. XAPM apm;
  1157. Xint lead;
  1158. Xint trail;
  1159. X{
  1160. X    int ercode = APM_OK;
  1161. X
  1162. X    apm_errno = APM_OK;
  1163. X
  1164. X    if (apm == (APM)NULL) {
  1165. X        return (APM_set_errno(APM_ENULL));
  1166. X    }
  1167. X
  1168. X    if (ercode >= APM_OK && lead) {
  1169. X        ercode = APM_trimlead(apm);
  1170. X    }
  1171. X
  1172. X    if (ercode >= APM_OK && trail) {
  1173. X        ercode = APM_trimtrail(apm);
  1174. X    }
  1175. X
  1176. X    if (ercode >= APM_OK) {
  1177. X        ercode = APM_normalize(apm);
  1178. X    }
  1179. X
  1180. X    return (APM_set_errno(ercode));
  1181. X}
  1182. X
  1183. Xint
  1184. XAPM_normalize(value)
  1185. XAPM value;
  1186. X{
  1187. X    static short *localData = (short *)NULL;
  1188. X    static int localLen = 0;
  1189. X    int len;
  1190. X    int dp;
  1191. X    int offset;
  1192. X    int ercode;
  1193. X
  1194. X    apm_errno = APM_OK;
  1195. X
  1196. X    ercode = APM_val_format(value);
  1197. X    if (ercode < APM_OK) {
  1198. X        return (ercode);
  1199. X    }
  1200. X    ercode = APM_val_base(value->base);
  1201. X    if (ercode < APM_OK) {
  1202. X        return (ercode);
  1203. X    }
  1204. X
  1205. X    if (value->dp >= 0 && value->length >= value->dp) {
  1206. X        return (APM_OK);
  1207. X    }
  1208. X
  1209. X    len = value->length;
  1210. X    if (value->length < value->dp) {
  1211. X        len = value->dp;
  1212. X        dp = value->dp;
  1213. X        offset = 0;
  1214. X    }
  1215. X    else if (value->dp < 0) {
  1216. X        len = value->length - value->dp;
  1217. X        dp = 0;
  1218. X        offset = -(value->dp);
  1219. X    }
  1220. X    else {
  1221. X        len = value->length;
  1222. X        dp = value->dp;
  1223. X        offset = 0;
  1224. X    }
  1225. X
  1226. X    if (len > localLen) {
  1227. X        int xlen = len;
  1228. X        if (xlen < 8) {
  1229. X            xlen = 8;
  1230. X        }
  1231. X        localData = (short *)APM_alloc_mem(localLen < 1 ?
  1232. X                        NULL : localData,
  1233. X                        xlen, sizeof (short));
  1234. X        if (localData == (short *)NULL) {
  1235. X            return (APM_set_errno(APM_ENOMEM));
  1236. X        }
  1237. X        localLen = xlen;
  1238. X    }
  1239. X
  1240. X    APM_zero_shorts(localData, len);
  1241. X    APM_copy_shorts(localData + offset, value->data, value->length);
  1242. X
  1243. X    ercode = APM_size(value, len);
  1244. X    if (ercode < APM_OK) {
  1245. X        return (ercode);
  1246. X    }
  1247. X
  1248. X    APM_copy_shorts(value->data, localData, len);
  1249. X
  1250. X    value->length = len;
  1251. X    value->dp = dp;
  1252. X
  1253. X    return (APM_OK);
  1254. X}
  1255. X
  1256. Xint
  1257. XAPM_setdp(result, value, dp)
  1258. XAPM result;
  1259. XAPM value;
  1260. Xint dp;
  1261. X{
  1262. X    int oldlen;
  1263. X    int newlen;
  1264. X    int voffset;
  1265. X    int roffset;
  1266. X    int ercode;
  1267. X
  1268. X    apm_errno = APM_OK;
  1269. X
  1270. X    ercode = APM_val_format(value);
  1271. X    if (ercode < APM_OK) {
  1272. X        return (ercode);
  1273. X    }
  1274. X    ercode = APM_val_base(value->base);
  1275. X    if (ercode < APM_OK) {
  1276. X        return (ercode);
  1277. X    }
  1278. X    if (result == value) {
  1279. X        return (APM_set_errno(APM_EOVERLAP));
  1280. X    }
  1281. X
  1282. X    ercode = APM_normalize(value);
  1283. X    if (ercode < APM_OK) {
  1284. X        return (ercode);
  1285. X    }
  1286. X
  1287. X    if (dp < 0) {
  1288. X        dp = value->dp;
  1289. X    }
  1290. X
  1291. X    oldlen = newlen = value->length;
  1292. X
  1293. X    if (dp <= value->dp) {
  1294. X        voffset = value->dp - dp;
  1295. X        roffset = 0;
  1296. X        oldlen -= voffset;
  1297. X    }
  1298. X    else {
  1299. X        voffset = 0;
  1300. X        roffset = dp - value->dp;
  1301. X        newlen += roffset;
  1302. X    }
  1303. X
  1304. X    ercode = APM_size(result, newlen);
  1305. X    if (ercode < APM_OK) {
  1306. X        return(ercode);
  1307. X    }
  1308. X
  1309. X    APM_zero_shorts(result->data, newlen);
  1310. X    APM_copy_shorts(result->data + roffset, value->data + voffset, oldlen);
  1311. X
  1312. X    result->sign = SIGNOF(value->sign);
  1313. X    result->base = value->base;
  1314. X    result->length = newlen;
  1315. X    result->dp = dp;
  1316. X    return (APM_OK);
  1317. X}
  1318. X
  1319. Xint
  1320. XAPM_norm_to_spec(apm)
  1321. XAPM apm;
  1322. X{
  1323. X    static APM localApm = (APM)NULL;
  1324. X    int length;
  1325. X    int locallen;
  1326. X    int localdp;
  1327. X    int ercode;
  1328. X    int n;
  1329. X    short sign;
  1330. X
  1331. X    apm_errno = APM_OK;
  1332. X
  1333. X    if (apm == (APM)NULL) {
  1334. X        return (APM_set_errno(APM_ENULL));
  1335. X    }
  1336. X
  1337. X    if (apm->base != 10) {
  1338. X        return (APM_set_errno(APM_EFMT));
  1339. X    }
  1340. X
  1341. X    length = apm->length;
  1342. X    sign = SIGNOF(apm->sign);
  1343. X    locallen = length;
  1344. X    localdp = ((apm->dp + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
  1345. X             * SPECIAL_SCALE;
  1346. X    locallen += (localdp - apm->dp);
  1347. X    locallen = ((locallen + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
  1348. X              * SPECIAL_SCALE;
  1349. X
  1350. X    if (localApm == (APM)NULL) {
  1351. X        localApm = APM_alloc();
  1352. X        if (localApm == (APM)NULL) {
  1353. X            return (APM_set_errno(APM_ENOMEM));
  1354. X        }
  1355. X    }
  1356. X    ercode = APM_size(localApm, locallen / SPECIAL_SCALE);
  1357. X    if (ercode < APM_OK) {
  1358. X        return (ercode);
  1359. X    }
  1360. X
  1361. X    for (n = 0; n < locallen; n += SPECIAL_SCALE) {
  1362. X        int value = 0;
  1363. X        int tn = n + (apm->dp - localdp);
  1364. X        if (tn >= 0 && tn < length) {
  1365. X            value += apm->data[tn];
  1366. X        }
  1367. X        ++tn;
  1368. X        if (tn >= 0 && tn < length) {
  1369. X            value += apm->data[tn] * 10;
  1370. X        }
  1371. X        ++tn;
  1372. X        if (tn >= 0 && tn < length) {
  1373. X            value += apm->data[tn] * 100;
  1374. X        }
  1375. X        ++tn;
  1376. X        if (tn >= 0 && tn < length) {
  1377. X            value += apm->data[tn] * 1000;
  1378. X        }
  1379. X        localApm->data[n / SPECIAL_SCALE] = value;
  1380. X    }
  1381. X    localApm->length = locallen / SPECIAL_SCALE;
  1382. X    localApm->dp = localdp / SPECIAL_SCALE;
  1383. X    localApm->sign = sign;
  1384. X    localApm->base = SPECIAL_BASE;
  1385. X
  1386. X    ercode = apm_assign(apm, localApm);
  1387. X
  1388. X    return (ercode);
  1389. X}
  1390. X
  1391. Xint
  1392. XAPM_spec_to_norm(apm)
  1393. XAPM apm;
  1394. X{
  1395. X    static APM localApm = (APM)NULL;
  1396. X    int length;
  1397. X    int locallen;
  1398. X    int n;
  1399. X    int ercode;
  1400. X    short sign;
  1401. X
  1402. X    apm_errno = APM_OK;
  1403. X
  1404. X    if (apm == (APM)NULL) {
  1405. X        return (APM_set_errno(APM_ENULL));
  1406. X    }
  1407. X
  1408. X    if (apm->base != SPECIAL_BASE) {
  1409. X        return (APM_set_errno(APM_EFMT));
  1410. X    }
  1411. X
  1412. X    ercode = APM_trim(apm, 1, 1);
  1413. X    if (ercode < APM_OK) {
  1414. X        return (APM_set_errno(APM_EFMT));
  1415. X    }
  1416. X
  1417. X    length = apm->length;
  1418. X    sign = SIGNOF(apm->sign);
  1419. X    if (localApm == (APM)NULL) {
  1420. X        localApm = APM_alloc();
  1421. X        if (localApm == (APM)NULL) {
  1422. X            return (APM_set_errno(APM_ENOMEM));
  1423. X        }
  1424. X    }
  1425. X    locallen = length * SPECIAL_SCALE;
  1426. X    ercode = APM_size(localApm, locallen);
  1427. X    if (ercode < APM_OK) {
  1428. X        return (ercode);
  1429. X    }
  1430. X    localApm->length = locallen;
  1431. X    localApm->sign = sign;
  1432. X    localApm->dp = apm->dp * SPECIAL_SCALE;
  1433. X    localApm->base = 10;
  1434. X
  1435. X    for (n = 0; n < length; ++n) {
  1436. X        int tn = n * SPECIAL_SCALE;
  1437. X        int value = apm->data[n];
  1438. X        int newvalue = value / 10;
  1439. X        localApm->data[tn] = value - (newvalue * 10);
  1440. X        value = newvalue;
  1441. X        newvalue = value / 10;
  1442. X        localApm->data[tn + 1] = value - (newvalue * 10);
  1443. X        value = newvalue;
  1444. X        newvalue = value / 10;
  1445. X        localApm->data[tn + 2] = value - (newvalue * 10);
  1446. X        value = newvalue;
  1447. X        newvalue = value / 10;
  1448. X        localApm->data[tn + 3] = value - (newvalue * 10);
  1449. X    }
  1450. X    ercode = apm_assign(apm, localApm);
  1451. X    if (ercode >= APM_OK) {
  1452. X        ercode = APM_trim(apm, 1, 1);
  1453. X    }
  1454. X    return (ercode);
  1455. X}
  1456. X
  1457. Xint
  1458. XAPM_size(apm, len)
  1459. XAPM apm;
  1460. Xint len;
  1461. X{
  1462. X    short *temp;
  1463. X    apm_errno = APM_OK;
  1464. X
  1465. X    if (len < 0) {
  1466. X        return (APM_set_errno(APM_EPARM));
  1467. X    }
  1468. X    if (apm == (APM)NULL) {
  1469. X        return (APM_set_errno(APM_ENULL));
  1470. X    }
  1471. X
  1472. X    if (len > apm->alloclen || apm->alloclen < 1) {
  1473. X        if (len < 8) {
  1474. X            len = 8;
  1475. X        }
  1476. X        if (apm->alloclen < 1) {
  1477. X            temp = (short *)APM_alloc_mem(NULL, len,
  1478. X                           sizeof (short));
  1479. X        }
  1480. X        else {
  1481. X            temp = (short *)APM_alloc_mem(apm->data, len,
  1482. X                           sizeof (short));
  1483. X        }
  1484. X        if (temp == (short *)NULL) {
  1485. X            return (APM_set_errno(APM_ENOMEM));
  1486. X        }
  1487. X        apm->data = temp;
  1488. X        apm->alloclen = len;
  1489. X    }
  1490. X
  1491. X    return (APM_OK);
  1492. X}
  1493. X
  1494. Xint
  1495. XAPM_parse_string(apm, string, base)
  1496. XAPM apm;
  1497. Xchar *string;
  1498. Xshort base;
  1499. X{
  1500. X    static char *localString = NULL;
  1501. X    static int localLen = 0;
  1502. X    int ercode;
  1503. X    int len;
  1504. X    int dp;
  1505. X    int special = 0;
  1506. X    short sign = 1;
  1507. X    char *temp;
  1508. X    short *bp;
  1509. X    char *tp;
  1510. X
  1511. X    apm_errno = APM_OK;
  1512. X
  1513. X    if (apm == (APM)NULL) {
  1514. X        return (APM_set_errno(APM_ENULL));
  1515. X    }
  1516. X
  1517. X    if (string == NULL) {
  1518. X        return (APM_set_errno(APM_ENULLVAL));
  1519. X    }
  1520. X
  1521. X    if (base == 0) {
  1522. X        base = SPECIAL_BASE;
  1523. X    }
  1524. X
  1525. X    ercode = APM_val_base(base);
  1526. X    if (ercode < APM_OK) {
  1527. X        return (ercode);
  1528. X    }
  1529. X
  1530. X    if (base == SPECIAL_BASE) {
  1531. X        special = 1;
  1532. X        base = 10;
  1533. X    }
  1534. X
  1535. X    len = strlen(string);
  1536. X    if (localString == NULL || localLen < len + 1) {
  1537. X        int xlen = len + 1;
  1538. X        if (xlen < 16) {
  1539. X            xlen = 16;
  1540. X        }
  1541. X        localString = APM_alloc_mem(localLen < 1 ? NULL : localString,
  1542. X                     xlen, sizeof (char));
  1543. X        if (localString == NULL) {
  1544. X            return (APM_set_errno(APM_ENOMEM));
  1545. X        }
  1546. X        localLen = xlen;
  1547. X    }
  1548. X    APM_copy_bytes(localString, string, len + 1);
  1549. X
  1550. X    temp = APM_trim_string(APM_left_justify(localString, " \t"));
  1551. X    if (*temp == '-') {
  1552. X        sign = -1;
  1553. X        ++temp;
  1554. X    }
  1555. X    else if (*temp == '+') {
  1556. X        sign = 1;
  1557. X        ++temp;
  1558. X    }
  1559. X
  1560. X    dp = APM_radix_pos(temp, base);
  1561. X    if (dp < 0) {
  1562. X        return (APM_set_errno(APM_EFMT));
  1563. X    }
  1564. X
  1565. X    len = strlen(temp);
  1566. X    if (dp > 0) {
  1567. X        char *sp = &temp[dp];
  1568. X        do {
  1569. X            sp[-1] = *sp;
  1570. X        } while (*sp++ != '\0');
  1571. X        --len;
  1572. X        dp = len - (dp - 1);
  1573. X    }
  1574. X
  1575. X    ercode = APM_size(apm, len);
  1576. X    if (ercode < APM_OK) {
  1577. X        return (ercode);
  1578. X    }
  1579. X
  1580. X    apm->base = base;
  1581. X    apm->length = len;
  1582. X    apm->dp = dp;
  1583. X    apm->sign = SIGNOF(sign);
  1584. X    for (bp = apm->data, tp = &temp[len]; tp-- > temp; ++bp) {
  1585. X        *bp = APM_get_digit(*tp, apm->base);
  1586. X    }
  1587. X
  1588. X    if (special) {
  1589. X        ercode = APM_norm_to_spec(apm);
  1590. X    }
  1591. X
  1592. X    if (ercode >= APM_OK) {
  1593. X        ercode = APM_trim(apm, 1, 1);
  1594. X    }
  1595. X
  1596. X    return (ercode);
  1597. X}
  1598. X
  1599. Xchar *
  1600. XAPM_build_string(string, data, length, dpos)
  1601. Xchar *string;
  1602. Xshort *data;
  1603. Xint length;
  1604. Xint dpos;
  1605. X{
  1606. X    short *bp;
  1607. X    int n = 0;
  1608. X
  1609. X    for (bp = &(data[length]); bp-- > data; ++n) {
  1610. X        if (n == dpos) {
  1611. X            *string++ = '.';
  1612. X        }
  1613. X        *string++ = APM_digits[*bp];
  1614. X    }
  1615. X    return (string);
  1616. X}
  1617. X
  1618. Xint
  1619. XAPM_parse_long(apm, value, base)
  1620. XAPM apm;
  1621. Xlong value;
  1622. Xshort base;
  1623. X{
  1624. X    int ercode;
  1625. X    int n;
  1626. X    long temp;
  1627. X
  1628. X    apm_errno = APM_OK;
  1629. X
  1630. X    if (apm == (APM)NULL) {
  1631. X        return (APM_set_errno(APM_ENULL));
  1632. X    }
  1633. X
  1634. X    if (base == 0) {
  1635. X        base = SPECIAL_BASE;
  1636. X    }
  1637. X    ercode = APM_val_base(base);
  1638. X    if (ercode < APM_OK) {
  1639. X        return (ercode);
  1640. X    }
  1641. X
  1642. X    apm->sign = 1;
  1643. X    apm->base = base;
  1644. X    apm->dp = 0;
  1645. X
  1646. X    if (value < 0) {
  1647. X        apm->sign = -1;
  1648. X        value = -value;
  1649. X    }
  1650. X
  1651. X    for (apm->length = 0, temp = value; temp != 0; temp /= base) {
  1652. X        ++(apm->length);
  1653. X    }
  1654. X    if (apm->length == 0) {
  1655. X        return (APM_OK);
  1656. X    }
  1657. X
  1658. X    ercode = APM_size(apm, apm->length);
  1659. X    if (ercode < APM_OK) {
  1660. X        return (ercode);
  1661. X    }
  1662. X
  1663. X    for (n = 0; n < apm->length; ++n) {
  1664. X        apm->data[n] = value % base;
  1665. X        value /= base;
  1666. X    }
  1667. X
  1668. X    return (APM_OK);
  1669. X}
  1670. X
  1671. Xshort
  1672. XAPM_array_add(result, addend, length, base)
  1673. Xshort *result;
  1674. Xshort *addend;
  1675. Xint length;
  1676. Xshort base;
  1677. X{
  1678. X    int n;
  1679. X    short tempval;
  1680. X    short carry = 0;
  1681. X
  1682. X    for (n = 0; n < length; ++n) {
  1683. X        tempval = result[n] + carry + addend[n];
  1684. X        result[n] = tempval % base;
  1685. X        carry = tempval / base;
  1686. X    }
  1687. X
  1688. X    return (carry);
  1689. X}
  1690. X
  1691. Xshort
  1692. XAPM_array_sub(result, subtrahend, length, base)
  1693. Xshort *result;
  1694. Xshort *subtrahend;
  1695. Xint length;
  1696. Xshort base;
  1697. X{
  1698. X    int n;
  1699. X    short tempval;
  1700. X    short borrow = 0;
  1701. X
  1702. X    for (n = 0; n < length; ++n) {
  1703. X        tempval = (result[n] + borrow) - subtrahend[n];
  1704. X        if (tempval < 0) {
  1705. X            result[n] = tempval + base;
  1706. X            borrow = -1;
  1707. X        }
  1708. X        else {
  1709. X            result[n] = tempval;
  1710. X            borrow = 0;
  1711. X        }
  1712. X    }
  1713. X    return (borrow);
  1714. X}
  1715. X
  1716. Xshort
  1717. XAPM_scalar_mul(result, multiplicand, length, multiplier, base)
  1718. Xshort *result;
  1719. Xshort *multiplicand;
  1720. Xint length;
  1721. Xshort multiplier;
  1722. Xshort base;
  1723. X{
  1724. X    int n;
  1725. X    long tempval;
  1726. X    short carry = 0;
  1727. X
  1728. X    for (n = 0; n < length; ++n) {
  1729. X        tempval = multiplicand[n];
  1730. X        tempval *= multiplier;
  1731. X        tempval += carry;
  1732. X        result[n] = (short)(tempval % base);
  1733. X        carry = (short)(tempval / base);
  1734. X    }
  1735. X    return (carry);
  1736. X}
  1737. X
  1738. Xint
  1739. XAPM_scalar_div(result, dividend, length, dp, sign, base, divisor)
  1740. XAPM result;
  1741. Xshort *dividend;
  1742. Xint length;
  1743. Xint dp;
  1744. Xshort sign;
  1745. Xshort base;
  1746. Xshort divisor;
  1747. X{
  1748. X    static APM apmDividend = (APM)NULL;
  1749. X    static APM apmDivisor = (APM)NULL;
  1750. X    int ercode;
  1751. X
  1752. X    apm_errno = APM_OK;
  1753. X
  1754. X    if (result == (APM)NULL || dividend == (short *)NULL) {
  1755. X        return (APM_set_errno(APM_ENULL));
  1756. X    }
  1757. X
  1758. X    if (apmDividend == (APM)NULL) {
  1759. X        apmDividend = APM_alloc();
  1760. X        if (apmDividend == (APM)NULL) {
  1761. X            return (APM_set_errno(APM_ENOMEM));
  1762. X        }
  1763. X    }
  1764. X    if (apmDivisor == (APM)NULL) {
  1765. X        apmDivisor = APM_alloc();
  1766. X        if (apmDivisor == (APM)NULL) {
  1767. X            return (APM_set_errno(APM_ENOMEM));
  1768. X        }
  1769. X        ercode = APM_size(apmDivisor, 1);
  1770. X        if (ercode < APM_OK) {
  1771. X            return (ercode);
  1772. X        }
  1773. X        apmDivisor->length = 1;
  1774. X        apmDivisor->dp = 0;
  1775. X    }
  1776. X
  1777. X    ercode = APM_size(apmDividend, length);
  1778. X    if (ercode < APM_OK) {
  1779. X        return (ercode);
  1780. X    }
  1781. X    APM_copy_shorts(apmDividend->data, dividend, length);
  1782. X
  1783. X    apmDividend->sign = sign;
  1784. X    apmDividend->length = length;
  1785. X    apmDividend->dp = dp;
  1786. X    apmDividend->base = base;
  1787. X
  1788. X    if (divisor < 0) {
  1789. X        apmDivisor->data[0] = -divisor;
  1790. X        apmDivisor->sign = -1;
  1791. X    }
  1792. X    else {
  1793. X        apmDivisor->data[0] = divisor;
  1794. X        apmDivisor->sign = 1;
  1795. X    }
  1796. X    apmDivisor->base = base;
  1797. X
  1798. X    return (apm_divide(result, length, (APM)NULL,
  1799. X               apmDividend, apmDivisor));
  1800. X}
  1801. X
  1802. Xint
  1803. XAPM_copy_bytes(to, from, num)
  1804. Xregister char *to;
  1805. Xregister char *from;
  1806. Xint num;
  1807. X{
  1808. X    register int n = num;
  1809. X
  1810. X    if (to == NULL || from == NULL || num <= 0) {
  1811. X        return (0);
  1812. X    }
  1813. X
  1814. X    if (to > from) {
  1815. X        to += n;
  1816. X        from += n;
  1817. X        while (n-- > 0) {
  1818. X            *(--to) = *(--from);
  1819. X        }
  1820. X    }
  1821. X    else if (to < from) {
  1822. X        while (n-- > 0) {
  1823. X            *to++ = *from++;
  1824. X        }
  1825. X    }
  1826. X
  1827. X    return (num);
  1828. X}
  1829. X
  1830. Xint
  1831. XAPM_zero_bytes(to, num)
  1832. Xregister char *to;
  1833. Xint num;
  1834. X{
  1835. X    register int n = num;
  1836. X
  1837. X    if (to == NULL || num <= 0) {
  1838. X        return (0);
  1839. X    }
  1840. X
  1841. X    while (n-- > 0) {
  1842. X        *to++ = 0;
  1843. X    }
  1844. X
  1845. X    return (num);
  1846. X}
  1847. X
  1848. Xint
  1849. XAPM_copy_shorts(to, from, num)
  1850. Xshort *to;
  1851. Xshort *from;
  1852. Xint num;
  1853. X{
  1854. X    return (APM_copy_bytes((char *)to, (char *)from,
  1855. X                num * sizeof (short)) / sizeof (short));
  1856. X}
  1857. X
  1858. Xint
  1859. XAPM_zero_shorts(to, num)
  1860. Xshort *to;
  1861. Xint num;
  1862. X{
  1863. X    return (APM_zero_bytes((char *)to,
  1864. X                num * sizeof (short)) / sizeof (short));
  1865. X}
  1866. X
  1867. Xchar *
  1868. XAPM_index(s, c)
  1869. Xregister char *s;
  1870. Xint c;
  1871. X{
  1872. X    if (s != NULL) {
  1873. X        for (; *s != '\0'; ++s) {
  1874. X            if (*s == (char)c) {
  1875. X                return (s);
  1876. X            }
  1877. X        }
  1878. X    }
  1879. X
  1880. X    return (NULL);
  1881. X}
  1882. X
  1883. Xvoid
  1884. XAPM_debug(va_alist)
  1885. Xva_dcl
  1886. X{
  1887. X    va_list ap;
  1888. X    char *format;
  1889. X    FILE *debug_file = apm_debug_file(NULL);
  1890. X
  1891. X    if (debug_file == (FILE *)NULL) {
  1892. X        return;
  1893. X    }
  1894. X
  1895. X    (void)apm_debug_file(debug_file);
  1896. X
  1897. X    va_start(ap);
  1898. X
  1899. X    format = va_arg(ap, char *);
  1900. X    if (format == NULL) {
  1901. X        return;
  1902. X    }
  1903. X
  1904. X    vfprintf(debug_file, format, ap);
  1905. X    fflush(debug_file);
  1906. X
  1907. X    va_end(ap);
  1908. X}
  1909. @\END_OF_FILE_utils.c
  1910. else
  1911.   echo "shar: Will not over write utils.c"
  1912. fi
  1913. echo "Finished archive 4 of 5"
  1914. # to concatenate archives, remove anything after this line
  1915. exit 0
  1916.